/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef TEMPLATES_H
#define TEMPLATES_H

#include "actions.h"
#include "cnome.h"
#include "directives.h"
#include "tokens.h"

namespace cnome {
template <typename ScannerT>
void
cpp::definition<ScannerT>::templates(cpp const& self)
    {
        using namespace actions;
        using namespace directive;
        using namespace util;

        template_declaration =
            pdp_d[ !EXPORT >> pdt_d[ TEMPLATE >> LESS >> template_parameter_list >> GREATER >> declaration ] ]//[&newTemplate_Name]
        ;

        template_parameter_list =
            template_parameter >> template_parameter_list_helper
        ;

        template_parameter_list_helper =
                ( COMMA >> template_parameter >> template_parameter_list_helper ) 
            |	EPSILON
        ;

        template_parameter =
                type_parameter        
            |	parameter_declaration 
        ;

        type_parameter =
               ( CLASS >> !(IDENTIFIER[&newTmplPrm]) >> !(ASSIGN >> pdp_d[ sss_d[ type_id ] ])    ) 
            |  ( TYPENAME >> !(IDENTIFIER[&newTmplPrm]) >> !(ASSIGN >> pdp_d[ sss_d[ type_id ] ]) ) 
            |  ( pdp_d[ TEMPLATE >> LESS >> pdt_d[ template_parameter_list ] >> GREATER >> CLASS >> !IDENTIFIER ]) 
            |  ( pdp_d[     TEMPLATE >> LESS >> pdt_d[ template_parameter_list ]>> GREATER >> CLASS >> !IDENTIFIER 
			      >>  !(ASSIGN >> pdt_d[ template_name ] ) ] ) 
        ;

        template_id =
            pdp_d[ template_name >> LESS >> pdt_d[ !template_argument_list ] >>	GREATER ]
        ;

        template_name =
			TEMPLATE_NAME
        ;

        template_argument_list =
            template_argument >> template_argument_list_helper
        ;

        template_argument_list_helper =
                ( COMMA >> template_argument >> template_argument_list_helper ) 
            |	EPSILON
        ;

        template_argument =
                assignment_expression 
            |	pdp_d[ sss_d[ type_id ]  ]
            |	template_name
        ;

        explicit_instantiation =
            template_declaration
        ;

        explicit_specialization =
            TEMPLATE >> LESS >> GREATER >> declaration
        ;
        //  End grammar definition
         
        // turn on the debugging info.
        BOOST_SPIRIT_DEBUG_RULE(template_parameter_list);
        BOOST_SPIRIT_DEBUG_RULE(declaration);
        BOOST_SPIRIT_DEBUG_RULE(template_parameter);
        BOOST_SPIRIT_DEBUG_RULE(template_parameter_list_helper);
        BOOST_SPIRIT_DEBUG_RULE(type_parameter);
        BOOST_SPIRIT_DEBUG_RULE(parameter_declaration);
        BOOST_SPIRIT_DEBUG_RULE(type_id);
        BOOST_SPIRIT_DEBUG_RULE(template_name);
        BOOST_SPIRIT_DEBUG_RULE(template_id);
        BOOST_SPIRIT_DEBUG_RULE(template_argument_list);
        BOOST_SPIRIT_DEBUG_RULE(template_argument);
        BOOST_SPIRIT_DEBUG_RULE(template_argument_list_helper);
        BOOST_SPIRIT_DEBUG_RULE(assignment_expression);
        BOOST_SPIRIT_DEBUG_RULE(explicit_instantiation);
        BOOST_SPIRIT_DEBUG_RULE(explicit_specialization);

        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE_NAME);

        BOOST_SPIRIT_DEBUG_RULE(EXPORT);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE);
        BOOST_SPIRIT_DEBUG_RULE(LESS);
        BOOST_SPIRIT_DEBUG_RULE(GREATER);
        BOOST_SPIRIT_DEBUG_RULE(COMMA);
        BOOST_SPIRIT_DEBUG_RULE(CLASS);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
        BOOST_SPIRIT_DEBUG_RULE(TYPENAME);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE);
        BOOST_SPIRIT_DEBUG_RULE(LESS);
        BOOST_SPIRIT_DEBUG_RULE(GREATER);
        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
    }
}  // namespace cnome
#endif // TEMPLATES_H
